from abc import ABC, abstractmethod
from django.db.models import QuerySet, Q

from users.models import HouseListing


class HouseListingAbstractFactory(ABC):
    """房源数据获取抽象工厂类"""

    @abstractmethod
    def get_house_detail(self, house_id: int) -> dict:
        """获取单个房源详情"""
        pass

    @abstractmethod
    def get_house_list(self, filters: dict = None,
                       ordering: str = '-id',
                       page: int = 1,
                       page_size: int = 10) -> dict:
        """获取房源列表"""
        pass


class HouseListingDBFactory(HouseListingAbstractFactory):
    """房源数据获取数据库实现工厂"""

    def get_house_detail(self, house_id: int) -> dict:
        """从数据库获取单个房源详情"""
        try:
            house = HouseListing.objects.select_related('landlord', 'type').get(id=house_id)
            return self._serialize_house_detail(house)
        except HouseListing.DoesNotExist:
            return None

    def get_house_list(self, filters: dict = None,
                       ordering: str = '-id',
                       page: int = 1,
                       page_size: int = 10) -> dict:
        """从数据库获取房源列表"""
        queryset = HouseListing.objects.select_related('type').all()

        # 应用过滤条件
        if filters:
            queryset = self._apply_filters(queryset, filters)

        # 应用排序
        if ordering:
            queryset = queryset.order_by(ordering)

        # 分页处理
        total_count = queryset.count()
        start = (page - 1) * page_size
        end = page * page_size
        paginated_queryset = queryset[start:end]

        house_list = [self._serialize_house_list_item(house) for house in paginated_queryset]

        return {
            'total': total_count,
            'page': page,
            'page_size': page_size,
            'total_pages': (total_count + page_size - 1) // page_size,
            'houses': house_list
        }

    def _serialize_house_detail(self, house: HouseListing) -> dict:
        """序列化房源详情"""
        return {
            'id': house.id,
            'landlord': {
                'id': house.landlord.id,
                'name': house.landlord.username
            },
            'title': house.title,
            'description': house.description,
            'address': house.address,
            'city': house.city,
            'district': house.district,
            'room_count': house.room_count,
            'bathroom_count': house.bathroom_count,
            'area': float(house.area),
            'price': float(house.price),
            'deposit': float(house.deposit) if house.deposit else None,
            'house_type': {
                'id': house.type.id,
                'name': house.type.name
            },
            'floor': house.floor,
            'total_floor': house.total_floor,
            'orientation': {
                'value': house.orientation,
                'display': dict(HouseListing.ORIENTATION_CHOICES).get(house.orientation)
            },
            'decoration_type': {
                'value': house.decoration_type,
                'display': dict(HouseListing.DECORATION_CHOICES).get(house.decoration_type)
            },
            'facilities': house.facilities or [],
            'images': house.images or [],
            'status': {
                'value': house.status,
                'display': dict(HouseListing.HOUSE_STATUS_CHOICES).get(house.status)
            },
            'create_time': house.create_time.isoformat(),
            'update_time': house.update_time.isoformat()
        }

    def _serialize_house_list_item(self, house: HouseListing) -> dict:
        """序列化房源列表项（简化版）"""
        return {
            'id': house.id,
            'title': house.title,
            'address': house.address,
            'city': house.city,
            'district': house.district,
            'room_count': house.room_count,
            'bathroom_count': house.bathroom_count,
            'area': float(house.area),
            'price': float(house.price),
            'deposit': float(house.deposit) if house.deposit else None,
            'house_type': house.house_type,  # 户型
            'type': {  # 房源类型
                'id': house.type.id,
                'name': house.type.name
            },
            'floor': house.floor,
            'total_floor': house.total_floor,
            'orientation': dict(HouseListing.ORIENTATION_CHOICES).get(house.orientation),
            'decoration_type': dict(HouseListing.DECORATION_CHOICES).get(house.decoration_type),
            'facilities': house.facilities or [],
            'images': house.images or [],
            'status': dict(HouseListing.HOUSE_STATUS_CHOICES).get(house.status),
        }

    def _apply_filters(self, queryset: QuerySet, filters: dict) -> QuerySet:
        """应用过滤条件到查询集"""
        # 简单字段过滤
        filter_mapping = {
            'city': 'city__icontains',
            'district': 'district__icontains',
            'status': 'status',
            'landlord_id': 'landlord_id',
            'type': 'type_id',
            'min_rooms': 'room_count__gte',
            'max_rooms': 'room_count__lte',
            'min_bathrooms': 'bathroom_count__gte',
            'max_bathrooms': 'bathroom_count__lte',
            'min_floor': 'floor__gte',
            'max_floor': 'floor__lte',
        }

        filter_kwargs = {}
        for param, field in filter_mapping.items():
            if param in filters:
                filter_kwargs[field] = filters[param]

        # 数值范围过滤
        range_filters = {
            'price': ('price__gte', 'price__lte'),
            'area': ('area__gte', 'area__lte'),
        }

        for field, (min_key, max_key) in range_filters.items():
            if f'min_{field}' in filters:
                filter_kwargs[min_key] = filters[f'min_{field}']
            if f'max_{field}' in filters:
                filter_kwargs[max_key] = filters[f'max_{field}']

        # 朝向过滤 (允许多选)
        orientations = filters.get('orientations')
        if orientations and isinstance(orientations, list):
            orientation_q = Q()
            for orient in orientations:
                orientation_q |= Q(orientation=orient)
            queryset = queryset.filter(orientation_q)

        # 装修类型过滤 (允许多选)
        decoration_types = filters.get('decoration_types')
        if decoration_types and isinstance(decoration_types, list):
            decoration_q = Q()
            for deco in decoration_types:
                decoration_q |= Q(decoration_type=deco)
            queryset = queryset.filter(decoration_q)

        # 配套设施过滤 (AND关系)
        facilities = filters.get('facilities')
        if facilities and isinstance(facilities, list):
            for facility in facilities:
                queryset = queryset.filter(facilities__contains=facility)

        # 关键词搜索 (标题和描述)
        keyword = filters.get('keyword')
        if keyword:
            queryset = queryset.filter(
                Q(title__icontains=keyword) |
                Q(description__icontains=keyword)
            )

        # 应用所有过滤条件
        return queryset.filter(**filter_kwargs)
